package com.kerrykidz.system.util.security;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.jdbc.core.RowCallbackHandler;

import com.kerrykidz.system.service.IUserService;
import com.kerrykidz.system.util.sync.SqlHelper;
import com.rdp.framework.exception.RDPException;
import com.rdp.util.config.SpringUtil;

/**
 * 
 * @ClassName: AuthRealm
 * @description: 用户登录认证及授权
 * @author: QUINN
 * @date: 2014年5月12日 下午4:10:05
 * @version: V1.0
 * 
 */
public class AuthRealm extends AuthorizingRealm {

	static final String USR_OBJ = "select a.* from gbl_sec_obj a inner join sec_role2obj c on a.pk_obj_id = c.fk_obj_id inner join sec_role d on c.fk_role_id = d.pk_role_id left join sec_obj2usr b on a.pk_obj_id = b.fk_obj_id where b.fk_usr_id=? and d.del_flag!='1'";

	static final String ROLE_OBJ = "select a.* from gbl_sec_obj a left join sec_role2obj b on a.pk_obj_id = b.fk_obj_id where b.fk_role_id in ( select pk_role_id from sec_role c inner join sec_role2usr d on c.pk_role_id = d.fk_role_id where d.fk_usr_id=? and c.del_flag!='1')";

	static final String ROLE_LIST = "select a.fk_role_id   from sec_role2usr a  inner join sec_role b on a.fk_role_id=b.pk_role_id  where fk_usr_id=? and b.del_flag!='1' group by a.fk_role_id";

	/**
	 * 授权
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		SimpleAuthorizationInfo author = new SimpleAuthorizationInfo();
		PrincipalInfo info = (PrincipalInfo) principals.getPrimaryPrincipal();

		Set<PermissionObj> objs = info.getPermissions();

		/*
		 * 设置菜单项到缓存里
		 */
		if (objs != null)
			for (PermissionObj bean : objs)
				author.addStringPermission(bean.getName());

		info.setPermissions(null);

		return author;
	}

	/**
	 * 认证
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

		/*
		 * 获取登录所需业务参数
		 */
		UsernamePasswordToken tok = (UsernamePasswordToken) token;
		String username = tok.getUsername();
		String password = new String(tok.getPassword());

		IUserService userService = SpringUtil.getBeanByType(IUserService.class);

		// 业务处理登录
		PrincipalInfo principal;
		try {
			principal = userService.checkLoginUser(username, password);
		} catch (RDPException e) {
			principal = null;
			e.printStackTrace();
		}
		if (principal == null)
			throw new IncorrectCredentialsException();

		final Set<PermissionObj> objs = new HashSet<PermissionObj>();

		SqlHelper.getJdbcTemplate().query(AuthRealm.ROLE_OBJ, new Object[] { principal.getUserId() },
				new RowCallbackHandler() {

					@Override
					public void processRow(ResultSet rs) throws SQLException {
						add2list(rs, objs);
					}

				});
		SqlHelper.getJdbcTemplate().query(AuthRealm.USR_OBJ, new Object[] { principal.getUserId() },
				new RowCallbackHandler() {
					@Override
					public void processRow(ResultSet rs) throws SQLException {
						add2list(rs, objs);
					}
				});
		principal.setPermissions(objs);

		List<PermissionObj> ps = new ArrayList<PermissionObj>();

		List<PermissionObj> other = new ArrayList<PermissionObj>();

		Iterator<PermissionObj> its = objs.iterator();
		while (its.hasNext()) {
			PermissionObj o = its.next();
			if ("1".equals(o.getType())) {
				ps.add(o);
				its.remove();
			}
			else if ("2".equals(o.getType()))
				other.add(o);
		}

		Collections.sort(ps);

		principal.setMenus(MenuUtils.getMenus(ps));

		Map<String, List<String>> urlsLink = new HashMap<String, List<String>>();

		Collections.sort(other);

		its = other.iterator();

		while (its.hasNext()) {
			PermissionObj o = its.next();
			List<String> links = urlsLink.get(o.getPid());
			if (links == null)
				links = new ArrayList<String>();
			links.add(o.getName());
			urlsLink.put(o.getPid(), links);
		}

		/**
		 * 设置角色
		 */
		final List<String> roles = new ArrayList<String>();
		SqlHelper.getJdbcTemplate().query(ROLE_LIST, new Object[] { principal.getUserId() }, new RowCallbackHandler() {

			@Override
			public void processRow(ResultSet rs) throws SQLException {
				roles.add(rs.getString("FK_ROLE_ID"));
			}
		});
		principal.setRoleList(roles);
		principal.setUrlsLinks(urlsLink);

		return new SimpleAuthenticationInfo(principal, password, getName());
	}

	private void add2list(ResultSet rs, Set<PermissionObj> objs) throws SQLException {
		PermissionObj obj = new PermissionObj();
		obj.setId(rs.getString("PK_OBJ_ID"));
		obj.setName(rs.getString("OBJ_NAME"));
		obj.setPadName(rs.getString("PAD_OBJ_NAME"));
		obj.setDesc(rs.getString("OBJ_DESC"));
		obj.setType(rs.getString("OBJ_TYPE"));
		obj.setOrdInd(rs.getInt("ORD_IND"));
		obj.setCssName(rs.getString("CSS_NAME"));
		obj.setPid(rs.getString("FK_PAROBJ_ID"));
		objs.add(obj);
	}

	@Override
	public void clearCache(PrincipalCollection principals) {
		super.clearCache(principals);
	}

	@Override
	public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
		super.clearCachedAuthenticationInfo(principals);
	}

	@Override
	public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
		super.clearCachedAuthorizationInfo(principals);
	}

	public void clearAllCache(PrincipalCollection principals) {
		super.getAuthenticationCache().clear();
		super.getAuthorizationCache().clear();
	}
}
